function GridView(gridcfg){
	
	/** self pointer */
	var _this = this;
	
	/** catalog */
	this.catalog;
	
	/** entity */
	this.entity;
	
	/** base path */
	this.baseDataPath = "/base/list/grid-data";
	this.baseConfigPath = "/base/list/config";
	this.baseEditViewPath = "/base/edit/view";
	this.baseDoEditPath = "/base/edit/do";
	this.baseDeletePath = "/base/delete/do";
	
	/** actually path */
	this.dataPath;
	this.configPath;
	this.editViewPath;
	this.editPath;
	this.deletePath;
	
	/*this.entityEditPath*/;
	
	this.updatePanel;
	this.updateForm;
	
	this.addPanel;
	this.addForm;
	
	this.delPanel;
	
	this.entityParam;
	this.dataset;
	this.id;
	this.data;
	this.config;
	this.grid;
	
	/** Init function */
	this.init = function(){
		
		_this.id = gridcfg.gridId;
		
		//dataset
		_this.dataset = gridcfg.dataset;
		var args = _this.dataset.split(/\./);
		_this.catalog = args[0];
		_this.entity = args[1];
		_this.entityParam = "?nebula_req_param_catalog="+_this.catalog+"&nebula_req_param_entity="+_this.entity;
		
		//config path
		if(isBlank(gridcfg.configPath)){
			_this.configPath = nebula.basePath + _this.baseConfigPath;
		}else{
			_this.configPath = nebula.basePath + gridcfg.configPath;
		}
		
		ajaxGet(_this.configPath,{"nebula_req_param_gridid":_this.id},function(json,status) {
			_this.config = json;
			
			// data path
			if(isBlank(_this.config.dataPath)){
				_this.dataPath = nebula.basePath + _this.baseDataPath;
			}else{
				_this.dataPath = nebula.basePath + _this.config.dataPath;
			}
			
			//edit view path
			if(isBlank(_this.config.editViewPath)){
				_this.editViewPath = nebula.basePath + _this.baseEditViewPath + _this.entityParam;
			}else{
				_this.editViewPath = nebula.basePath + _this.config.editViewPath;
			}
			
			//edit path
			if(isBlank(_this.config.editPath)){
				_this.editPath = nebula.basePath + _this.baseDoEditPath + _this.entityParam;
			}else{
				_this.editPath = nebula.basePath + _this.config.editPath;
			}
			
			//delete path
			if(isBlank(_this.config.deletePath)){
				_this.deletePath = nebula.basePath + _this.baseDeletePath + _this.entityParam;
			}else{
				_this.deletePath = nebula.basePath + _this.config.deletePath;
			}
			_this.updatePanel = $("#updateModal");
			_this.updateForm = _this.updatePanel.find("form");
			
			_this.addPanel = $("#addModal");
			_this.addForm = _this.addPanel.find("form");
			
			_this.delPanel = $("#deleteModal");
			
			_this.createGrid();
			_this.createFootActions();
			_this.addGridListener();
			
		},false);
	};
	
	this.onComplete = function(){
		var header = new Array();
		$("#"+_this.id + ">thead>tr>th").each(function(){
			header.push($(this).text());
		});

		$("#"+_this.id + ">tbody>tr").each(function(){
			$(this).find("td").each(function(index){
				$(this).attr("resp-title",header[index]);
			});
		});
	};
	
	this.createFootActions = function(){
		
		if(_this.config.footActions == undefined || _this.config.footActions == null){
			return ;
		}
		
		var footActions = _this.config.footActions;
		if(footActions.buttons == undefined || footActions.buttons == null){
			return ;
		}
		
		var panel = $("#"+_this.id).closest(".panel-body");
		for (var i = 0; i < footActions.buttons.length; i++) {
			var button = footActions.buttons[i];
			panel.append(_this.createButton(button));
		}
	};
	
	this.createButton = function(button){
		var btnText = button.text == undefined || button.text == null ? "":button.text;
		return "<a action='"+button.action+"' href='javascript:;' class='btn "+button.clazz+"'><i class='"+button.icon+"'></i> "+btnText+" </a> ";
	};
	
	this.defaultButtonRender = function(column){
		return function(data, type, full){
			var html = "";
			for (var i = 0; i < column.buttons.length; i++) {
				var button = column.buttons[i];
				if(button.action == undefined || button.action == null){
					continue;
				}
				/*if(button.params != undefined && button.params != null){
					for (var j = 0; j < button.params.length; j++) {
						var param = button.params[j];
						//button.action = button.action.replace(new RegExp("\@\{"+param.name+"\}\@","g"),data[param.value]);
					}
				}*/
				html += _this.createButton(button);
			}
			return html;
		};
	};
	
	this.getRender = function(name){
		return function(data, type, full){
			eval(name)(data, type, full);
		};
	};
	
	this.addGridListener = function(){
		
		$("#"+_this.id + " > tbody").on('click','a.btn', function (e) {
			var data = _this.grid.row($(this).parents('tr')).data();
			eval($(this).attr("action"))($(this),data,e);
		});
		
		
		$("#"+_this.id).closest(".panel-body").find("> a.btn").bind("click",function(e){
			eval($(this).attr("action"))($(this),e);
		});
		
		$("#"+_this.id).on('draw.dt', function (e, settings, json) {
			if(_this.config.tree){
				_this.createTreeGrid();
			}
			_this.onComplete();
		});
		
	};
	
	this.getColumnDefs = function(){
		var columns = new Array();
		var columnDefs = new Array();
		for (var i = 0; i < _this.config.columns.length; i++) {
			var column = _this.config.columns[i];
			var colData = {};
			var colDef = {};
			
			if(column.buttons != null && column.buttons.length > 0 ){
				colDef["targets"] = i;
				colDef["render"] = _this.defaultButtonRender(column);
			}else if(column.jsrender !=undefined && column.jsrender !=null){
				colDef["targets"] = i;
				colDef["render"] = eval(column.jsrender);
			}
			if(column.width !=undefined && column.width !=null){
				colDef["width"] = column.width;
			}
			
			colData["data"] = column.property;
			colData["title"] = column.label;
			colData["width"] = column.width;
			
			columnDefs.push(colDef);
			columns.push(colData);
		}
		return {"columns":columns,"columnDefs":columnDefs};
	};
	
	this.treeGridInit = false;
	this.treeGridExpandNodes = new Array();
	
	this.createTreeGrid = function(force){
		
		$("#"+_this.id + ">tbody>tr").each(function(){
			var data = _this.grid.row(this).data();
			$(this).attr("data-tt-id",data.pkid);
			if(data.parentPkid != undefined && data.parentPkid != null){
				$(this).attr("data-tt-parent-id",data.parentPkid);
			}
		});
		
		$("#"+_this.id).treetable({ 
			expandable: true,
			onNodeExpand : function(){
				var id = $(this)[0].id;
				if($.inArray(id,_this.treeGridExpandNodes) < 0){
					_this.treeGridExpandNodes.push(id);
				}
			},
			onNodeCollapse: function(){
				var id = $(this)[0].id;
				var index = $.inArray(id,_this.treeGridExpandNodes);
				_this.treeGridExpandNodes.splice(index,1);
			}
		},force);
		//$("#"+_this.id).treetable("collapseAll");
		for (var i = 0; i < _this.treeGridExpandNodes.length; i++) {
			$("#"+_this.id).treetable("expandNode", _this.treeGridExpandNodes[i]);
		}
	};
	
	this.createGrid = function(){
		
		var columnDefs =_this.getColumnDefs();
		
		_this.grid = $("#"+_this.id).DataTable({
			"bProcessing": true,
			"bInfo":true,
			"bAutoWidth":false,
			"bFilter":false,
			"lengthChange":false,
			'paging': this.config.page,
			"pageLength" : this.config.pageSize,
			"ordering" : !this.config.tree,
			//'bScrollInfinite':true,
			'pagingType': 'simple_numbers',
			//"data":_this.data,
			"ajax" : {
				"url":addUrlParams(_this.dataPath,"nebula_req_param_gridid="+_this.id),
				"dataSrc": ""
			},
			//"serverSide": true,
			"language": {  
				"processing": "正在加载数据...",  
				"lengthMenu": "每页显示 _MENU_ 项记录",  
				"zeroRecords": "没有符合条件的数据...",  
				"info": "当前 _START_ ～ _END_ 项，合计 _TOTAL_ 项",  
				"infoEmpty": "共 0 项",
				"paginate" : {
					"next" : "下一页",
					"previous" : "上一页"
				}
			},
			"columns": columnDefs["columns"],
			"columnDefs": columnDefs["columnDefs"]
		});
		
	};
	
	this.update = function(target,data,e){
		_this.updateForm[0].reset();
		_this.updatePanel.modal();
		_this.updateForm.bind("submit",_this.doUpdate);
		
		var pkstr = _this.config.pk+"="+data[_this.config.pk];
		ajaxGet(_this.editViewPath,{'nebula_req_param_querypk':pkstr},function(data,status) {
			fillFormWithJson(_this.updateForm[0],data);
			_this.updateForm.find("input[name='nebula_req_param_querypk']").attr("value",pkstr);
		});
		
	};
	
	this.add = function(target,e){
		_this.addForm[0].reset();
		_this.addPanel.modal();
		_this.addForm.bind("submit",_this.doAdd);
	};
	
	this.del = function(target,data,e){
		_this.delPanel.modal();
		_this.delPanel.find(".modal-body button").bind("click",function(){
			var pkstr = _this.config.pk+"="+data[_this.config.pk];
			_this.doDelete(pkstr);
		});
	};
	
	this.doUpdate = function(){
		if(_this.updateForm.valid()){
			var submit = _this.updateForm.find("button[type='submit']");
			submit.button('loading');
			ajaxPost(_this.editPath,getJsonFromForm(_this.updateForm),function(data,status) {
				submit.button('reset');
				_this.updateForm.unbind('submit');
				_this.updatePanel.modal("hide");
				_this.reload();
			});
		}
		return false;
	};
	
	this.doAdd = function(){
		if(_this.addForm.valid()){
			var submit = _this.addForm.find("button[type='submit']");
			submit.button('loading');
			ajaxPost(_this.editPath,getJsonFromForm(_this.addForm),function(data,status) {
				submit.button('reset');
				_this.addForm.unbind('submit');
				_this.addPanel.modal("hide");
				_this.reload();
			});
		};
		return false;
	};
	
	this.doDelete = function(pkstr){
		ajaxGet(_this.deletePath,{'nebula_req_param_querypk':pkstr},function(data,status) {
			_this.delPanel.find(".modal-body button").unbind('click');
			_this.delPanel.modal("hide");
			_this.reload();
		});
	};
	
	this.query = function(queryid,querystr){
		var url = _this.dataPath;
		url = addUrlParams(url,"nebula_req_param_queryid="+queryid);
		url = addUrlParams(url,"nebula_req_param_gridid="+_this.id);
		_this.grid.ajax.url(addUrlParams(url,querystr)).load();
	};
	
	this.reload = function(){
		_this.grid.ajax.reload(function(){
			if(_this.config.tree){
				_this.createTreeGrid(true);
			};
		});
	};
	
	this.init();
}
